#include "stdio.h"
#include "stdlib.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "unistd.h"
#include "linux/input.h"
#include "string.h"

/* 用于描述多点触摸的每点信息 */
typedef struct ts_tm {
    int x;
    int y;
    int id;
    int valid;  // >0 
}ts_tm_t;

/* 一个触摸点的x、y坐标信息 */
typedef struct tp_xy {
    int x;
    int y;
}tp_xy_t;

/* 读取触摸点信息 */
int ts_read(int fd, const int max_slot, ts_tm_t *mt) 
{
    struct input_event in_ev;
    static int slot = 0;
    static tp_xy_t xy[12] = {0};
    int i, len;

    /* 清空缓存 */
    memset(mt, 0x00, max_slot*sizeof(ts_tm_t));
    
    /* valid赋初值 */
    for (i=0; i<max_slot; i++) {
        mt[i].id = -2;      //将 id 初始化为-2, id=-1 表示触摸点删除, id>=0 表示创建
    }

    len = sizeof(struct input_event);
    
    while (1) {
        if ( read(fd, &in_ev, len) != len ) {
            perror("read error");
            exit(EXIT_FAILURE);
        }

        /* 解析数据 */
        switch (in_ev.type) {
            case EV_ABS:
                switch (in_ev.code) {
                    case ABS_MT_SLOT:
                        slot = in_ev.value;
                        break;

                    case ABS_MT_POSITION_X:
                        xy[slot].x = in_ev.value;                       
                        mt[slot].valid = 1;
                        break;

                    case ABS_MT_POSITION_Y:
                        xy[slot].y = in_ev.value;                      
                        mt[slot].valid = 1;
                        break;

                    case ABS_MT_TRACKING_ID:
                        mt[slot].id = in_ev.value;
                        mt[slot].id = 1;
                         break;
                }
                break;

            case EV_SYN:
                if (in_ev.code == SYN_REPORT) {         // 注意if判断中的等号问题，是两个 == ！！！
                    for (i=0; i<max_slot; i++) {
                        mt[i].x = xy[i].x;
                        mt[i].y = xy[i].y;
                    }
                }
                return 0;
        }
    }
}

int main(int argc, char *argv[])
{
    struct input_absinfo slot;
    ts_tm_t *mt = NULL;
    int max_slot;
    int fd;
    int i;

    /* 参数校验 */
    if (argc != 2) {
        fprintf(stderr, "usage:%s<input_dev>\n", argv[0]);
        exit(EXIT_FAILURE);
    } 

    /* 打开文件 */
    if ((fd = open(argv[1], O_RDONLY)) < 0) {
        perror("open error");
        exit(EXIT_FAILURE);
    }

    /* 获取触摸屏支持的最大触摸点数 */
    if (0 > ioctl(fd, EVIOCGABS(ABS_MT_SLOT), &slot)) {
        perror("ioctl error");
        exit(EXIT_FAILURE);
    }

    max_slot = slot.maximum + 1 - slot.minimum;
    printf("max_slot:%d\n",max_slot);

    /* 申请内存空间并清零 */
    mt = calloc(max_slot, sizeof(ts_tm_t));

    /* 读数据 */
    while (1) {
        if (ts_read(fd, max_slot, mt) < 0) {
            printf("ts_read < 0\n");
            break;
        }

        for (i=0; i<max_slot; i++) {
            if (mt[i].valid) {
                if (mt[i].id >= 0) {
                    printf("slot<%d>, 按下(%d, %d)\n", i, mt[i].x, mt[i].y);
                } else if (mt[i].id == -1) {
                    printf("slot<%d>, 松开\n", i);
                } else {
                    printf("slot<%d>, 移动(%d, %d)\n", i, mt[i].x, mt[i].y);
                }
            }
        }
    }

    close(fd);
    free(mt);   
    exit(EXIT_SUCCESS);
}